#include "serialtchannel.h"
#ifdef WIN32
#define usleep(x) Sleep(x)
#endif
#include "business_def.h"
#include "pfunc_time.h"
#include "Log.h"

class UpdateThread : public acl::thread
{
public:
    UpdateThread(SerialTChannel *ptr_STC_);
    ~UpdateThread();
    void* run();
private:
    bool running;
    SerialTChannel *ptr_STC;
};

UpdateThread::UpdateThread(SerialTChannel *ptr_STC_)
    : running(true)
    , ptr_STC(ptr_STC_)
{

}

UpdateThread::~UpdateThread()
{
    running = false;
    ptr_STC = NULL;
}

void* UpdateThread::run()
{
    while (running)
    {
        if(NULL!=ptr_STC){
            ptr_STC->updateData();
        }
        usleep(10);
    }
    return NULL;
}

//////////////////////////////////////////////////////
float SerialTChannel::com_base_limit = float(0.000001);
SerialTChannel::SerialTChannel(int tid_)
    : TranChannel(tid_)
    , running(true)
    , serial_open_flag(false)
    , open_fail_log(true)
    , serial_data_ut(pyfree::getCurMsTime())
{
    init(tid_);
    ptr_UT = new UpdateThread(this);
    ptr_UT->start();
}

SerialTChannel::~SerialTChannel()
{
    running = false;
    stopSms();
}

void* SerialTChannel::run()
{
    char ret_buf[256]={0};
    char except_buf[256]={0};
    while(running)
    {
        // updateData();
        if(serial_open_flag)
        {
            if(m_ssg.read_cmd(ret_buf,256,except_buf,256))
            {
                printf("read_cmd:%s\n",ret_buf);
                this->AddFrameFromUp((const unsigned char*)ret_buf,(int)strlen(ret_buf));
            }
        }else{
            startSms();
        }
        usleep(10);
    }
    return NULL;
}

void SerialTChannel::init(int tid_)
{
    BusinessDef *ptrBDef = BusinessDef::getInstance();
    if(!ptrBDef->getSerialInfoByTID(tid_,serialarg))
    {
        Print_WARN("getSerialInfoByTID error!\n");
    }
    if(!ptrBDef->getPOS(serial_data))
    {
        Print_WARN("serial_data is empty!\n");
    }
    //单次m_ssg读取时间=readCount*readSleep
	m_ssg.setReadCount(serialarg.readCount);//数据读取次数
	m_ssg.setReadSleep(serialarg.readSleep);//数据读取等待
}

//开启任务
bool SerialTChannel::startSms()
{
	char arg_[64]={0};
	sprintf(arg_, "%d%s%d", serialarg.DataBit,serialarg.Parity.c_str(),serialarg.StopBit);
	int ret = m_ssg.Open(tatts.name.c_str(), serialarg.BaudRate, arg_,ctb::SerialPort::NoFlowControl);
	if( -1 ==  ret)
	{
        if(open_fail_log){
            open_fail_log = false;
            CLogger::createInstance()->Log(MsgError,
                    "SerialTranID(%d) open serical(%s %d,%s) fail! [%s %s %d]"
                    , tatts.id, tatts.name.c_str(), serialarg.BaudRate, arg_
                    , __FILE__, __FUNCTION__, __LINE__);
        }
		return false;
	}
	serial_open_flag = true;
    open_fail_log = true;
    CLogger::createInstance()->Log(MsgInfo,
			"SerialTranID(%d,%s)  be open successful![%s %s %d]"
			, tatts.id, tatts.name.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
	return true;
}

//关闭
void SerialTChannel::stopSms()
{
	try{
		if (!serial_open_flag)
		{
			return;
		}
		serial_open_flag = false;
        open_fail_log = true;
		m_ssg.Close();
#ifdef DEBUG
		Print_NOTICE("m_ssg.Close()\n");
#endif
	}catch(...){
        //Print_NOTICE("SerialTChannel::stopSms fail\n");
		CLogger::createInstance()->Log(MsgError,
			"SerialTChannel::stopSms SerialTranID(%d,%s) fail![%s %s %d]"
			, tatts.id, tatts.name.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
    }
}

bool SerialTChannel::serialDataUp(ChannelToTransmit item)
{
    //写入缓存
    bool update_ = false;
    serial_mutex.Lock();
    std::map<int,LiveData>::iterator it = serial_data.find(item.pID);
    if(it!=serial_data.end())
    {
        unsigned long cur_usec = pyfree::getCurMsTime();
        if(abs(it->second.value - item.val)>com_base_limit)     //值被改变
        {
            update_ = true;
            if(2==serialarg.com_model)  //值改变而发送,全局记录时刻变更,可以防止再次发送造成拼帧
            {
                serial_data_ut = cur_usec;
            }
        }
        if(2==serialarg.com_model&&(serial_data_ut+serialarg.readSleep)<cur_usec)//全局记录时刻距当前达到readSleepms
        {
            update_ = true;
            serial_data_ut = cur_usec;
        }
        if(3==serialarg.com_model&&(it->second.update_time+serialarg.readSleep)<cur_usec)//单点记录时刻距当前达到readSleepms
        {
            update_ = true;
        }
        if(update_){
            it->second.type = item.pType;
            it->second.value = item.val;
            it->second.update_time = cur_usec;
        }
    }
    serial_mutex.Unlock();
    return update_;
}

void SerialTChannel::updateData()
{
    ChannelToTransmit item;
	if(WriteDataS->pop(item))
    {
        bool update = serialDataUp(item);
        if(2==serialarg.com_model)
        {
            //双向通信,全态势推送
            if(update){
                responseForAll(item.taskID,item.changeF);
            }
        }else{
            //应答通信
            std::map<int,float> pinfos;
            unsigned long taskID = 0L;
            if(3==serialarg.com_model)
            {
                if(update){
                    pinfos[item.pID] = item.val;
                    taskID = item.taskID;
                }
            }else{
                
                //查找等待控制返回的信息点,恢复对上层响应
                unsigned long cur_usec = pyfree::getCurMsTime();
                response_mutex.Lock();
                std::list<PTO_STATE>::iterator itp = response_point.begin();
                while (itp != response_point.end())
                {
                    if(itp->pid==(int)item.pID)
                    {
                        //需要有10-300毫秒后的返回才算下控返回
                        if((itp->rep_time+1000)>cur_usec
                            &&(itp->rep_time+10)<cur_usec)
                        {
                            pinfos[itp->pid] = item.val;
                            taskID = item.taskID;
                            itp = response_point.erase(itp);
                            continue;
                        }
                    }
                    //超时控制返回对上层响应已失效,删除
                    if((itp->rep_time+1000)<cur_usec)
                    {
                        itp = response_point.erase(itp);
                        continue;
                    }
                    itp++;
                }
                response_mutex.Unlock();
            }
            std::string pinfo_vals_desc = "";
            if(getInfoValDesc(pinfos,pinfo_vals_desc))
            {
                sendCmd(pinfo_vals_desc,(int)pyfree::OnSet,taskID,item.changeF);
                if(3==serialarg.com_model)//防止发送太快造成拼帧
                {
                    usleep(10); //暂时固定设值10ms,因此上层应用读取数据超时最好不要超过10ms,防止造成拼帧需要做分帧处理
                }
            }
        }
    }
}

int SerialTChannel::AddFrameFromUp(const unsigned char *buf, int len)
{
    //
    QueueData<TransmitToGChannel> trans_;
    int ret =  this->AddFrameByLua((const unsigned char*)buf, len,trans_);
    dispatchFromUp(trans_);
    return ret;
}

void SerialTChannel::dispatchFromUp(QueueData<TransmitToGChannel> trans_)
{
    //当前版本只限定总召查询/单点查询/单点控制
    TransmitToGChannel item;
    int size = trans_.size();
    printf("-----------------1--------------------\n");
    while (trans_.pop(item))
    {
        // printf("item(%d,%d,%.2f)\n",item.pID,(int)item.pType,item.val);
        this->ToGchannelDatas->add(item);
        if(1==serialarg.com_model)
        { 
            if(1==size&&0==item.pID&&item.exeType==pyfree::OnGet)
            {
                //总召
                responseForAll(item.taskID);
            }
            if(1==size&&item.pID>0&&item.exeType==pyfree::OnSet)
            {
                //单点控制,需要等待控制返回,因此需要延迟处理
                ToGchannelDatas->add(item);
                //是否态势变更
                bool change_flag = true;
                serial_mutex.Lock();
                std::map<int,LiveData>::iterator it = serial_data.find(item.pID);
                if(it!=serial_data.end())
                {
                    if(abs(it->second.value-item.val)<com_base_limit)
                    {
                        change_flag = false;
                    }
                }
                serial_mutex.Unlock();
                if(change_flag){
                    PTO_STATE pto_;
                    pto_.pid = item.pID;
                    pto_.ptype = item.pType;
                    pto_.value = item.val;
                    pto_.rep_time = pyfree::getCurMsTime();   
                    pto_.taskID = item.taskID;
                    response_mutex.Lock();
                    response_point.push_back(pto_);
                    response_mutex.Unlock();
                }else{
                    //无变化直接返回
                    printf("-----------------2--------------------\n");
                    responseForPonit(item.pID,1,(int)pyfree::OnSet,item.taskID);
                }
            }
            if(1==size&&item.pID>0&&item.exeType==pyfree::OnGet)
            {
                //指定点查询
                responseForPonit(item.pID,static_cast<unsigned int>(item.val),(int)pyfree::OnGet,item.taskID);
            }
        }
    }
}

void SerialTChannel::responseForAll(unsigned long taskID/*=0L*/,bool changeF/*=false*/)
{
    std::map<int,float> pinfos;
    serial_mutex.Lock();
    std::map<int,LiveData>::iterator it=serial_data.begin();
    while (it!=serial_data.end())
    {
        pinfos[it->first]=it->second.value;
        it++;
    }
    serial_mutex.Unlock();
    std::string pinfo_vals_desc = "";
    if(getInfoValDesc(pinfos,pinfo_vals_desc))
    {
        sendCmd(pinfo_vals_desc,1,taskID,changeF);
    }
}

void SerialTChannel::responseForPonit(unsigned int pid
    , unsigned int psize/*=1*/,unsigned int respType/*=1*/,unsigned long taskID/*=0L*/)
{
    std::map<int,float> pinfos;
    serial_mutex.Lock();
    std::map<int,LiveData>::iterator it = serial_data.find(pid);
    //容器已经进行了排序,直接按需从开始点获取需要的点,如果点配置不连续也没关系,不用在配置文件做额外限定
    while(it!=serial_data.end()&&pinfos.size()<psize)
    {
        pinfos[it->first]=it->second.value;
        it++;
    }
    serial_mutex.Unlock();
    std::string pinfo_vals_desc = "";
    if(getInfoValDesc(pinfos,pinfo_vals_desc))
    {
        sendCmd(pinfo_vals_desc,respType,taskID);
    }
}

bool SerialTChannel::getInfoValDesc(std::map<int,float> pinfos,std::string &ret)
{
    if(pinfos.empty())
        return false;
    ret="";
    char buf[64]={0};
    std::map<int,float>::iterator it=pinfos.begin();
    while (it!=pinfos.end())
    {
        sprintf(buf,"%d,%.2f;",it->first,it->second);
        ret+=std::string(buf);
        it++;
    }
    if(!ret.empty()){
        // ret.pop_back();//需要-std=c++11
        ret = ret.substr(0,ret.length() - 1);
    }
    return !ret.empty();
}

void SerialTChannel::sendCmd(std::string pinfo_vals_desc
    , unsigned int respType/*=1*/,unsigned long taskID/*=0L*/,bool changeF/*=false*/)
{
    unsigned char cmd[256]={0};
    if(getResponseByLua(cmd,256,pinfo_vals_desc,respType,taskID,changeF)>0)
    {
        // printf("resp_cmd:%s\n",cmd);
        char exception[256]={0};
        if(!m_ssg.write_cmd((const char*)cmd,(int)strlen((char*)cmd),exception,256))
        {
            CLogger::createInstance()->Log(MsgError,
                "SerialTranID(%d) write_cmd(%s) error(%s). [%s %s %d]"
                , tatts.id, cmd, exception
                , __FILE__, __FUNCTION__, __LINE__);
        }
    }
}
